package com.xu.demo.common.components;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * redisTemplate工具类
 */
@Slf4j
@Component
public class RedisTemplateUtil implements Serializable {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    /**
     * 判断redis中是否含有该键
     *
     * @param key 键值
     * @return Boolean值 false 没有此键， true 含有此键
     */
    public boolean hasKey(String key) {
        return Optional.ofNullable(redisTemplate)
                .map(template -> template.hasKey(key)).isPresent();
    }

    /**
     * 获取键的过期时间
     *
     * @param key 键
     * @return 返回long类型的时间数值
     */
    public Long getExpire(String key) {
        return redisTemplate.getExpire(key);
    }

    /**
     * 过期时间设置
     *
     * @param key           键
     * @param expireMinutes 过期时间
     * @return 返回设置成功
     */
    public boolean setExpire(String key, long expireMinutes) {
        return Boolean.TRUE.equals(redisTemplate.expire(key, Duration.ofMinutes(expireMinutes)));
    }

    public boolean setExpireByMillis(String key, long expireMillis) {
        return Boolean.TRUE.equals(redisTemplate.expire(key, Duration.ofMillis(expireMillis)));
    }

    public boolean setExpireBySecond(String key, long expireSeconds) {
        return Boolean.TRUE.equals(redisTemplate.expire(key, Duration.ofSeconds(expireSeconds)));
    }

    public boolean setExpireByHour(String key, long expireHours) {
        return Boolean.TRUE.equals(redisTemplate.expire(key, Duration.ofHours(expireHours)));
    }

    public boolean setExpireByDay(String key, long expireDays) {
        return Boolean.TRUE.equals(redisTemplate.expire(key, Duration.ofMinutes(expireDays)));
    }

    /**
     * 删除键值
     *
     * @param key 键
     * @return 返回删除结果
     */
    public boolean delete(String key) {
        return Optional.ofNullable(redisTemplate)
                .map(template -> template.delete(key)).isPresent();
    }

    /**
     * 通过集合中的所有key删除对应的所有值
     *
     * @param keys 集合keys
     * @return 返回boolean值
     */
    public boolean delete(Collections keys) {
        return Optional.ofNullable(redisTemplate)
                .map(template -> template.delete(keys)).isPresent();
    }

    //-----------------------------对象键值存取---------------------------------------------------------------

    /**
     * 存值
     *
     * @param key   键
     * @param value 值
     */
    public void set(Object key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 存值
     *
     * @param key    键
     * @param value  值
     * @param offset 位置
     */
    public void set(Object key, Object value, long offset) {
        redisTemplate.opsForValue().set(key, value, offset);
    }

    /**
     * 存值
     *
     * @param key     键
     * @param value   值
     * @param timeout 过期时间
     */
    public void set(String key, Object value, Duration timeout) {
        redisTemplate.opsForValue().set(key, value, timeout);
    }

    /**
     * 存值
     *
     * @param key      键
     * @param value    值
     * @param timeout  过期时间
     * @param timeUnit 时间单位
     */
    public void set(Object key, Object value, long timeout, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }

    /**
     * 获取键对应的值
     *
     * @param key 键
     * @return 返回键对应的值
     */
    public Object get(Object key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 获取键对应的值
     *
     * @param key   键
     * @param start 开始位置
     * @param end   结束位置
     * @return 返回范围内的对应键的值
     */
    public Object get(Object key, long start, long end) {
        return redisTemplate.opsForValue().get(key, start, end);
    }

    /**
     * 获取键对应的值的大小
     *
     * @param key 键
     * @return 大小
     */
    public Long getSize(Object key) {
        return Optional.ofNullable(redisTemplate)
                .map(template -> template.opsForValue().size(key)).orElse(null);

    }

    //-----------------------------String键值存取---------------------------------------------------------------

    /**
     * 存值
     *
     * @param key   键
     * @param value 值
     */
    public void set(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 存值
     *
     * @param key    键
     * @param value  值
     * @param offset 位置
     */
    public void setByOffset(String key, String value, long offset) {
        redisTemplate.opsForValue().set(key, value, offset);
    }

    /**
     * 存值
     *
     * @param key     键
     * @param value   值
     * @param timeout 过期时间 可以使用Duration来调用相关时间参数
     */
    public void set(String key, String value, Duration timeout) {
        redisTemplate.opsForValue().set(key, value, timeout);
    }

    /**
     * 存值（时间封装）
     *
     * @param key     键
     * @param value   值
     * @param minutes 过期时间 分钟
     */
    public void set(String key, String value, long minutes) {
        redisTemplate.opsForValue().set(key, value, Duration.ofMinutes(minutes));
    }

    public void setBySeconds(String key, String value, long seconds) {
        redisTemplate.opsForValue().set(key, value, Duration.ofSeconds(seconds));
    }

    public void setByHour(String key, String value, long hours) {
        redisTemplate.opsForValue().set(key, value, Duration.ofHours(hours));
    }

    public void setByDay(String key, String value, long days) {
        redisTemplate.opsForValue().set(key, value, Duration.ofDays(days));
    }

    /**
     * 存值
     *
     * @param key      键
     * @param value    值
     * @param timeout  过期时间
     * @param timeUnit 时间单位
     */
    public void set(String key, String value, long timeout, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }

    /**
     * 获取键对应的值
     *
     * @param key 键
     * @return 返回键对应的值
     */
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 获取键对应的值
     *
     * @param key   键
     * @param start 开始位置
     * @param end   结束位置
     * @return 返回范围内的对应键的值
     */
    public Object get(String key, long start, long end) {
        return redisTemplate.opsForValue().get(key, start, end);
    }

    //-----------------------------List键值存取---------------------------------------------------------------

    /**
     * 根据key存储到list的指定位置
     *
     * @param key   键
     * @param index list中指定索引
     * @param value 值
     */
    public void lSet(Object key, long index, Object value) {
        redisTemplate.opsForList().set(key, index, value);
    }

    /**
     * 存储到列表最左侧
     *
     * @param key   键
     * @param value 值
     */
    public void lSet(Object key, Object value) {
        redisTemplate.opsForList().leftPush(key, value);
    }

    /**
     * 存储到列表最左
     *
     * @param key   键
     * @param pivot 值
     * @param value 值
     */
    public void lSet(Object key, Object pivot, Object value) {
        redisTemplate.opsForList().leftPush(key, pivot, value);
    }

    /**
     * 存储到列表最右
     *
     * @param key   键
     * @param value 值
     */
    public void lSetR(Object key, Object value) {
        redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     * 存储到列表最右
     *
     * @param key   键
     * @param value 值
     */
    public void lSetR(Object key, Object pivot, Object value) {
        redisTemplate.opsForList().rightPush(key, pivot, value);
    }

    /**
     * 获取对应key的list列表大小
     *
     * @param key 键
     * @return size
     */
    public long lGetSize(Object key) {
        return redisTemplate.opsForList().size(key);
    }

    /**
     * 获取键对应的列表数据
     *
     * @param key 键
     * @return key的值（列表）
     */
    public List lGet(Object key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

    /**
     * 获取键对应的列表数据
     *
     * @param key   键
     * @param start 开始位置
     * @param end   结束位置
     * @return 返回key对应范围内的列表数据
     */
    public List lGet(Object key, long start, long end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    //-----------------------------Set(无序)键值存取---------------------------------------------------------------

    /**
     * 存储set类型的数据
     *
     * @param key    键
     * @param values 值，可以是多个
     */
    public void sSet(Object key, Object... values) {
        redisTemplate.opsForSet().add(key, values);
    }

    /**
     * 获取key对应set类型数据的大小
     *
     * @param key 键
     */
    public long sGetSize(Object key) {
        return redisTemplate.opsForSet().size(key);
    }

    /**
     * 获取set类型的数据
     *
     * @param key 键
     * @return 返回一个set集合
     */
    public Set sGet(Object key) {
        return redisTemplate.opsForSet().members(key);
    }

    //-----------------------------ZSet(有序)键值存取---------------------------------------------------------------

    /**
     * 存储有序集合
     *
     * @param key   键
     * @param value 值
     * @param score 排序
     */
    public void zSet(Object key, Object value, double score) {
        redisTemplate.opsForZSet().add(key, value, score);
    }

    /**
     * 存储值
     *
     * @param key 键
     * @param set 集合
     */
    public void zSet(Object key, Set<ZSetOperations.TypedTuple<Object>> set) {
        redisTemplate.opsForZSet().add(key, set);
    }

    /**
     * 获取key指定范围的值
     *
     * @param key   键
     * @param start 开始位置
     * @param end   结束位置
     * @return 返回set
     */
    public Set zGet(Object key, long start, long end) {
        return redisTemplate.opsForZSet().range(key, start, end);
    }

    /**
     * 获取key对应的所有值
     *
     * @param key 键
     * @return 返回set
     */
    public Set zGet(Object key) {
        return redisTemplate.opsForZSet().range(key, 0, -1);
    }

    /**
     * 获取对用数据的大小
     *
     * @param key 键
     * @return 键值大小
     */
    public long zGetSize(Object key) {
        return redisTemplate.opsForZSet().size(key);
    }

    //-----------------------------HashMap键值存取---------------------------------------------------------------

    /**
     * 存储hashMap数据
     *
     * @param key     键
     * @param hashKey map的id
     * @param value   值
     */
    public void hSet(Object key, Object hashKey, Object value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    /**
     * 获取大小
     *
     * @param key 键
     */
    public void hGetSize(Object key) {
        redisTemplate.opsForHash().size(key);
    }

    /**
     * 获取hashMap数据
     *
     * @param key     键
     * @param hashKey map的id
     * @return 返回值
     */
    public Object hGet(Object key, Object hashKey) {
        return redisTemplate.opsForHash().get(key, hashKey);
    }

    /**
     * 删除数据
     *
     * @param key      键
     * @param hashKeys map的id
     * @return 返回Boolean
     */
    public Object hDel(Object key, Object... hashKeys) {
        return redisTemplate.opsForHash().delete(key, hashKeys);
    }

}
